import '../public/styles/replace.css';

// 基础模块导入（这些模块暂时保持独立导入）
import { IBaseLayer } from './map/layers/BaseLayer';
import { SharedTextLayer } from './bizUnit/shared/sharedTextLayer';
import { ObjectModelManager } from './model';
import { INavigateOptions } from './features/navigate';
import logger from 'loglevel';

// 通过共享模块导入所有类型和功能
import {
  // 类型定义
  BizUnitType,
  IBizUnitNameAndConfig,
  IBizUnitConfig,
  ModelObjType,
  TNavigationControlPosition,
  TMapSourceConfig,
  // 应用层
  SourceLoadingManager,
  IDataLoadingStrategy,
  // 功能模块
  NavigationManager,
  ZoomManager,
  // 地图核心
  MapCore,
  // 工具类
  EventBus,
  useProxyFetch,
} from './shared';
import {
  BizUnit,
  ConnectorBizUnit,
  EnergystoreBizUnit,
  HeatplantBizUnit,
  MeasuredpointBizUnit,
  PartprestationBizUnit,
  PipelineBizUnit,
  PumpBizUnit,
  SubstationBizUnit,
  TeeBizUnit,
  ValveBizUnit,
} from './bizUnit';

// 导出共享模块
export * from './shared';
export * from './bizUnit';

const ModelSourceId = 'model-source';
const ModelObjType2BizUnitClass: Record<
  ModelObjType,
  new (...args: any[]) => BizUnit
> = {
  heatplant: HeatplantBizUnit,
  energystore: EnergystoreBizUnit,
  partprestation: PartprestationBizUnit,
  substation: SubstationBizUnit,
  pump: PumpBizUnit,
  valve: ValveBizUnit,
  measuredpoint: MeasuredpointBizUnit,
  tee: TeeBizUnit,
  connector: ConnectorBizUnit,
  pipeline: PipelineBizUnit,
};
// type TMapSourceKey = keyof typeof MapSource

export class EngiGis {
  mapCore: MapCore;
  zoom!: ZoomManager;
  // private mapLayer!: IMapLayer;
  private layers: IBaseLayer[] = [];
  private sharedLayers: Record<
    'iconTextLayer' | 'textLayer',
    IBaseLayer
  > | null = null;
  private hasInteractionInit = false;
  private bizUnitMap: Map<string, BizUnit> = new Map();

  bus: EventBus = new EventBus();
  objectModelManager!: ObjectModelManager;
  // 考虑把 filter 能力直接放在 layer 里面
  // private filters: [string, FilterBuilder][] = [];
  showProperties: string[] = [];

  // 添加性能监控配置
  private performanceConfig = {
    enableDetailedLogging: false, // 是否启用详细日志
    maxConsoleOutputs: 100, // 最大console输出数量
    consoleOutputCount: 0,
  };

  // 受控的console输出方法
  private safeLog(message: string, data?: any) {
    if (
      this.performanceConfig.consoleOutputCount <
      this.performanceConfig.maxConsoleOutputs
    ) {
      console.log(message, data || '');
      this.performanceConfig.consoleOutputCount++;
    }
  }

  get map() {
    return this.mapCore.map;
  }

  /**
   * 导航管理器 - 处理地图跳转功能
   * @private
   */
  private navigationManager!: NavigationManager;

  constructor(
    container: string | HTMLElement,
    mapSource: TMapSourceConfig,
    options?: { navigationControlPosition: TNavigationControlPosition },
  ) {
    // 1. 初始化全局代理， 用于避免mapbox问题
    useProxyFetch();
    // this.mapLayer = mapLayer;
    // const map = this.loadMap(container, mapSource);
    // this.map = map;
    this.mapCore = new MapCore(container, mapSource);
    this.zoom = this.mapCore.zoomManager;
    // todo 整合 onload
    this.mapCore.map.on('load', () => {
      if (options?.navigationControlPosition) {
        this.showNavigationControl(options.navigationControlPosition);
      }

      logger.info(this.layers, 'layers');
    });
  }

  /**
   * 根据模型类型获取对应的图层
   * @param modelType 模型类型
   * @returns 对应的图层或undefined
   */
  getLayerByModelType(modelType: ModelObjType): IBaseLayer | undefined {
    return this.layers.find((layer) => layer.layerId.includes(modelType));
  }

  /**
   * 显示地图导航控件（包含缩放按钮）
   * @param position 控件位置，默认为右上角
   */
  private showNavigationControl(
    position: TNavigationControlPosition = 'top-right',
  ): void {
    return this.mapCore.showNavigationControl(position);
  }

  /**
   * 隐藏地图导航控件
   */
  hideNavigationControl(): void {
    this.mapCore.hideNavigationControl();
  }

  /**
   * 跳转到指定坐标
   * @param coordinates 目标坐标 [经度, 纬度]
   * @param options 跳转选项
   * @returns Promise，在动画完成时解析
   */
  async flyToCoordinates(
    coordinates: [number, number],
    options: INavigateOptions = {},
  ): Promise<void> {
    return this.navigationManager.flyToCoordinates(coordinates, options);
  }

  /**
   * 跳转到指定对象
   * @param objectId 对象ID
   * @param sourceId 数据源ID，默认为'model-source'
   * @param options 跳转选项
   * @returns Promise，在动画完成并结束突出显示时解析
   */
  async flyToObject(objectId: string, objType?: ModelObjType): Promise<void> {
    this.mapCore.onceMapLoaded(() => {
      this.navigationManager.flyToObject(objectId, objType);
    });
  }

  /**
   * 适配显示所有内容
   * 优先使用缓存的边界信息，如果没有缓存则会重新计算
   * @param options 导航选项
   * @returns Promise，在动画完成时解析
   */
  fitAllContent(options: INavigateOptions = {}): Promise<void> {
    if (!this.navigationManager) {
      throw new Error(
        '导航管理器尚未初始化，请在地图加载完成后再尝试适配全部内容',
      );
    }

    return this.navigationManager.fitAllContent(options);
  }

  getSharedTextLayer(): SharedTextLayer {
    return this.getSharedLayer('textLayer') as SharedTextLayer;
  }

  private getSharedLayer(layerName: 'iconTextLayer' | 'textLayer'): IBaseLayer {
    if (!this.sharedLayers) {
      throw new Error('共享图层尚未初始化，请先调用 async init() 方法');
    }
    const layer = this.sharedLayers[layerName];
    if (!layer) {
      throw new Error(`共享图层 ${layerName} 不存在`);
    }
    return layer;
  }

  async initSharedLayers() {
    if (this.sharedLayers) {
      throw new Error('共享图层已经初始化过了');
    }

    console.time('🔍 initSharedLayers总耗时');
    performance.mark('initSharedLayers-start');

    const TextLayerId = 'shared_text_layer';
    const omm = this.objectModelManager;

    console.time('🔍 获取模型数据耗时');
    const modelObjGisInfoSource = await omm.getModelObjectGisInfoSource();
    console.timeEnd('🔍 获取模型数据耗时');

    // 检查数据量大小
    const dataSize = JSON.stringify(modelObjGisInfoSource).length;
    const featureCount =
      (modelObjGisInfoSource.data as any)?.features?.length || 0;
    console.log('📊 数据量统计:', {
      dataSize: `${(dataSize / 1024 / 1024).toFixed(2)}MB`,
      featureCount,
      memoryUsage: (performance as any).memory
        ? {
            used: `${((performance as any).memory.usedJSHeapSize / 1024 / 1024).toFixed(2)}MB`,
            total: `${((performance as any).memory.totalJSHeapSize / 1024 / 1024).toFixed(2)}MB`,
          }
        : 'Not available',
    });

    // 🎯 数据量优化：如果数据过大，实施分级策略
    let optimizedSource = modelObjGisInfoSource;
    if (featureCount > 10000) {
      console.info('💡 数据量过大，已启用性能优化策略');
      optimizedSource = this.optimizeDataForPerformance(
        modelObjGisInfoSource,
        featureCount,
      );
    }

    console.time('🔍 添加数据源耗时');
    const sourceId = await this.addOrUpdateSource(
      ModelSourceId,
      optimizedSource as mapboxgl.GeoJSONSourceSpecification,
    );
    console.timeEnd('🔍 添加数据源耗时');

    const sharedTextLayer = new SharedTextLayer({
      layerId: TextLayerId,
      sourceId,
      map: this.map,
      sort: 0, // 至高无上的文字图层 POWER!!!
    });
    // const sharedLineLayer = new SharedLineLayer('lineLayer', sourceId)
    this.sharedLayers = {
      textLayer: sharedTextLayer,
      // lineLayer: sharedLineLayer
    } as any;
    sharedTextLayer.addToMap();
    this.layers.push(sharedTextLayer);
    this.updateLayersSorting();
    performance.mark('initSharedLayers-end');
    performance.measure(
      'initSharedLayers-total',
      'initSharedLayers-start',
      'initSharedLayers-end',
    );
    console.timeEnd('🔍 initSharedLayers总耗时');

    // 📈 输出性能统计
    const measures = performance
      .getEntriesByType('measure')
      .filter((m) => m.name.includes('initSharedLayers'));
    if (measures.length > 0) {
      console.log(
        '🎯 性能统计:',
        measures.map((m) => `${m.name}: ${m.duration.toFixed(2)}ms`),
      );
    }

    logger.info('共享图层初始化完成');
  }

  /**
   * 数据性能优化策略
   */
  private optimizeDataForPerformance(source: any, featureCount: number) {
    const features = (source.data as any).features;
    console.time('🔍 数据优化处理耗时');

    // 策略1: 按重要性分级（优先显示重要设施）
    const priorityTypes = ['heatplant', 'substation', 'partprestation']; // 重要设施优先
    const priorityFeatures = features.filter((f: any) =>
      priorityTypes.includes(f.properties?.type),
    );

    // 策略2: 地理分布采样（避免密集区域过载）
    const sampledFeatures = this.spatialSampling(
      features,
      Math.min(5000, featureCount * 0.3),
    );

    // 策略3: 合并优先级和采样结果
    const optimizedFeatures = [
      ...priorityFeatures,
      ...sampledFeatures.filter(
        (f: any) => !priorityTypes.includes(f.properties?.type),
      ),
    ].slice(0, 8000); // 最多显示8000个要素

    const optimizedSource = {
      ...source,
      data: {
        ...source.data,
        features: optimizedFeatures,
      },
    };

    console.timeEnd('🔍 数据优化处理耗时');
    console.log(
      `📈 数据优化完成: ${featureCount} → ${optimizedFeatures.length} 个要素`,
    );

    return optimizedSource;
  }

  /**
   * 空间采样算法 - 避免地理位置过于密集
   */
  private spatialSampling(features: any[], targetCount: number) {
    if (features.length <= targetCount) return features;

    // 简单的网格采样
    const gridSize = 0.001; // 约100米网格
    const grid = new Map<string, any>();

    for (const feature of features) {
      if (feature.geometry?.coordinates) {
        const [lng, lat] = feature.geometry.coordinates;
        const gridKey = `${Math.floor(lng / gridSize)},${Math.floor(lat / gridSize)}`;

        // 每个网格只保留一个要素（可以改进为保留最重要的）
        if (!grid.has(gridKey)) {
          grid.set(gridKey, feature);
        }
      }
    }

    const sampledFeatures = Array.from(grid.values());
    return sampledFeatures.slice(0, targetCount);
  }
  /**
   * 添加或更新地图数据源， 此操作会自动更新渲染效果
   */
  addOrUpdateSource(
    sourceId: string,
    source: mapboxgl.GeoJSONSourceSpecification,
  ): Promise<string> {
    // 使用 MapCore 的策略加载方法
    return this.mapCore.addOrUpdateSourceWithStrategy(sourceId, source, {
      safeLog: this.safeLog.bind(this),
      performanceConfig: this.performanceConfig,
    });
  }

  /**
   * 初始化 内置 BizUnits , 并使当前实例关联 ObjectModelManager
   * 1. 建立EngiGis和 ObjectModelManager 的关联关系
   * 2. 调用 ObjectModelManager 的 init 方法进行初始化
   * 3. 加载全部的模型数据
   * 4. 添加 source 到 mapboxgljs 实例
   * @param omm
   * @param projectName
   * @param modelType
   * @param userGroupIds
   * @param userId
   * @returns
   */
  async initBuiltInBizUnits(
    omm: ObjectModelManager,
    projectName: string,
    modelType: string,
    userGroupIds: number[],
    userId: number,
  ): Promise<void> {
    if (this.objectModelManager) {
      throw new Error('ObjectModelManager 已经被初始化过了');
    }
    this.navigationManager = new NavigationManager(this.mapCore.map, omm);
    this.objectModelManager = omm;
    const modelObjInfoList = await omm.init(
      projectName,
      modelType,
      userGroupIds,
      userId,
    );
    // 1. 初始化共享图层
    await this.initSharedLayers();
    // 2. 初始化内置 bizUnits
    await this.initBuiltInBizUnitsRenderer(
      modelObjInfoList.map(
        (m) =>
          ({
            name: m.key,
            config: {
              sort: m.sort || 0,
            },
          }) as IBizUnitNameAndConfig,
      ),
    );
  }

  showText(properties: string[]) {
    return this.getSharedTextLayer().showText(properties);
  }

  /**
   * 初始化交互事件
   * 1. 检查是否已经初始化过交互事件
   * 2. 如果没有初始化，则根据业务单元列表获取对应的图层
   * 3. 添加点击事件交互，处理点击事件并触发对应的事件
   * @param bizUnits 业务单元列表
   */
  private initInteractions(bizUnits: BizUnit[] = []) {
    if (!this.hasInteractionInit) {
      const layers = bizUnits
        .map((bizUnit) => bizUnit?.layerId)
        .filter((id) => id !== undefined);
      this.hasInteractionInit = true;
      this.mapCore.addInteraction('click', {
        type: 'click',
        layers,
        handler: (event) => {
          try {
            const feature = event.feature;
            const layerId = feature.layer.id;
            const objType = layerId.split('_')[0] as ModelObjType;
            if (!objType) {
              console.warn('点击事件没有找到对应的对象类型');
              return false;
            }
            const properties = {
              ...feature.properties,
              nmap: JSON.parse(feature.properties.nmap || '{}'),
              zoom: JSON.parse(feature.properties.zoom || '{}'),
            };
            this.bus.emit(`click:layer`, {
              objType: objType,
              properties,
              _origin: event,
            });
          } catch (error) {
            console.error(
              `处理点击事件时发生错误, 请检查图层${event?.feature?.layer?.id}`,
              error,
            );
            return false;
          }
          return true;
        },
      });
    }
  }

  /**
   * 渲染指定业务单元
   * 1. 根据业务单元名称列表，获取对应的业务单元类
   * 2. 实例化业务单元类，并传入共享文本图层
   * 3. 调用业务单元的 render 方法进行渲染
   * @param {{name: BizUnitType, sort: number }} layers  业务单元名称列表
   * @param {boolean} isUpdate 是否为更新操作，默认为false
   */
  async initBuiltInBizUnitsRenderer(
    data: IBizUnitNameAndConfig[],
  ): Promise<{ bizUnit: BizUnit; config: IBizUnitConfig }[]> {
    console.time('🔍 业务单元初始化总耗时');
    performance.mark('bizUnits-init-start');

    const tobeRenderList = data
      .map((d) => {
        let bizUnit: BizUnit | null = null;
        const bizUnitClass = ModelObjType2BizUnitClass[d.name as ModelObjType];
        if (!bizUnitClass) {
          console.warn(`未找到内置业务单元类: ${d.name}`);
          bizUnit = null; // 如果没有找到对应的业务单元类，返回null
        } else {
          bizUnit = new bizUnitClass(this);
        }
        return { bizUnit, config: d.config };
      })
      .filter((bizUnit) => bizUnit !== null);

    console.log(`📊 准备渲染 ${tobeRenderList.length} 个业务单元`);

    if (tobeRenderList?.length) {
      this.initInteractions(tobeRenderList.map(({ bizUnit }) => bizUnit!));
    }

    // 使用分批处理，避免一次性处理所有业务单元
    const BATCH_SIZE = 3; // 每批处理3个
    const results: { bizUnit: BizUnit; config: IBizUnitConfig }[] = [];

    for (let i = 0; i < tobeRenderList.length; i += BATCH_SIZE) {
      const batch = tobeRenderList.slice(i, i + BATCH_SIZE);
      console.time(`🔍 批次${Math.floor(i / BATCH_SIZE) + 1}处理耗时`);

      await Promise.all(
        batch.map(async ({ bizUnit, config }) => {
          performance.mark(`bizUnit-${bizUnit!.unitType}-start`);
          await this.addBizUnit(bizUnit!, config);
          performance.mark(`bizUnit-${bizUnit!.unitType}-end`);
          performance.measure(
            `bizUnit-${bizUnit!.unitType}`,
            `bizUnit-${bizUnit!.unitType}-start`,
            `bizUnit-${bizUnit!.unitType}-end`,
          );
          return { bizUnit: bizUnit!, config };
        }),
      );

      console.timeEnd(`🔍 批次${Math.floor(i / BATCH_SIZE) + 1}处理耗时`);
      results.push(
        ...(batch as { bizUnit: BizUnit; config: IBizUnitConfig }[]),
      );

      // 让出主线程，避免长时间阻塞
      await new Promise((resolve) => setTimeout(resolve, 0));
    }

    performance.mark('bizUnits-init-end');
    performance.measure(
      'bizUnits-init-total',
      'bizUnits-init-start',
      'bizUnits-init-end',
    );
    console.timeEnd('🔍 业务单元初始化总耗时');

    return results;
  }

  private updateLayersSorting() {
    const layers = this.layers.sort((a, b) => b.sort - a.sort);
    layers.forEach((layer) => {
      this.mapCore.setLayerTop(layer.layerId);
    });
  }

  /**
   * 更新指定类型模型对象的可见性
   * @param modelType 模型类型
   * @param visible 是否可见
   * @param affectsText 是否影响文字
   */
  private updateLayerVisible(
    modelType: ModelObjType,
    visible: boolean,
    affectsText: boolean = true,
  ) {
    // 更新特定类型模型的可见性
    const layer = this.getLayerByModelType(modelType);
    if (layer) {
      layer.setVisible(visible);
    } else {
      console.error(`未找到模型类型 ${modelType} 的图层，无法更新可见性`);
    }
    if (affectsText) {
      const sharedTextLayer = this.getSharedTextLayer();
      if (sharedTextLayer) {
        // 如果影响文字图层，则更新其可见性
        sharedTextLayer.updateVisibleByObjType(modelType, visible);
      }
    }
  }

  /**
   * 批量更新模型对象的可见性
   */
  async updateLayersVisible(
    data: { modelType: ModelObjType; visible: boolean }[],
  ): Promise<void> {
    data.forEach((item) => {
      this.updateLayerVisible(item.modelType, item.visible);
    });
    const sharedTextLayer = this.getSharedTextLayer();
    if (sharedTextLayer) {
      // 如果影响文字图层，则更新其可见性
      // sharedTextLayer.setFilterObjTypes(data.map(item => item.modelType));
      sharedTextLayer.batchUpdateVisibleByObjTypes(data);
    }
  }

  /**
   * 更新实时数据
   * 此方法会调用 bizUnit.update, 默认会把传入的properties对象合并到现有数据中
   * 可 override bizUnit.update, 实现自定义更新逻辑
   * @param unitType 模型对象类型
   * @param data 对象id和properties对象
   */
  async updateRealTimeData(
    data: {
      unitType: BizUnitType;
      update: { id: string; properties: Record<string, any> }[];
    }[],
  ): Promise<void> {
    if (!this.objectModelManager) {
      throw new Error(
        'ObjectModelManager 尚未初始化，请先调用 initBuiltInBizUnits 方法',
      );
    }
    for (const { unitType, update } of data) {
      this.updateSourceForBizUnit(unitType, update);
    }
  }

  private async updateSourceForBizUnit(
    unitType: BizUnitType,
    update: { id: string; properties: Record<string, any> }[],
  ) {
    const bizUnit = this.bizUnitMap.get(unitType);
    if (!bizUnit) {
      throw new Error(`未找到业务单元 ${unitType}，请确保已添加该业务单元`);
    }
    return bizUnit.update(update);
    // return this.mapCore.updateSourceWithProperties(`${unitType}_source`, update)
  }

  async addBizUnit(bizUnit: BizUnit, config: IBizUnitConfig): Promise<void> {
    if (!(bizUnit instanceof BizUnit)) {
      throw new Error('添加的业务单元必须是 BizUnit 的实例');
    }
    if (this.bizUnitMap.has(bizUnit.unitType)) {
      throw new Error(`业务单元 ${bizUnit.unitType} 已经存在`);
    }
    this.bizUnitMap.set(bizUnit.unitType, bizUnit);
    // 1. 先初始化地理数据到source
    await bizUnit.updateGeoData(config);
    // 2. 再设置渲染器
    await bizUnit.setRenderer(config).then((layers: IBaseLayer[]) => {
      for (const layer of layers) {
        if (this.layers.find((l) => l.layerId === layer.layerId)) {
          logger.warn(`图层 ${layer.layerId} 已经存在，跳过添加`);
          continue; // 如果图层已经存在，跳过
        }
        layer.addToMap();
        this.layers.push(layer);
      }
      this.updateLayersSorting();
      // 添加图层到地图
      // bizUnit.addLayersToMap(layers, this, this.mapCore.map);
      logger.info(`${bizUnit.unitType}图层已添加`);
      // return Promise.all(layers.map(layer => {
      // return this.addLayerIfNotExists(layer)

      // }))
    });
    logger.info(`业务单元 ${bizUnit.unitType} 已添加`);
    // 如果已经初始化了交互事件，则重新初始化
    // todo 这里如何追加交互
    // this.initInteractions([bizUnit]);
  }

  /**
   * 获取数据加载管理器（用于高级配置）
   */
  getDataLoadingManager(): SourceLoadingManager {
    return this.mapCore.getDataLoadingManager();
  }

  /**
   * 配置数据加载策略
   * @param options 配置选项
   */
  configureDataLoading(options: {
    chunkSize?: number;
    enableWebWorker?: boolean;
    customStrategies?: IDataLoadingStrategy[];
  }) {
    // 如果需要自定义分片大小，可以在这里重新配置策略
    if (options.customStrategies) {
      // 清除现有策略并添加自定义策略
      options.customStrategies.forEach((strategy) => {
        this.mapCore.registerLoadingStrategy(strategy);
      });
    }

    // 记录配置变更
    this.safeLog('🔧 数据加载策略已更新', options);
  }
}

export * from './model';
